{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "d5d2bc77",
   "metadata": {
    "scrolled": true
   },
   "outputs": [],
   "source": [
    "import torch\n",
    "import torchvision\n",
    "import torchvision.transforms as transforms\n",
    "import torch.nn as nn\n",
    "import torch.nn.functional as F\n",
    "import torch.optim as optim\n",
    "import matplotlib.pyplot as plt\n",
    "import numpy as np\n",
    "import math\n",
    "\n",
    "\n",
    "\n",
    "import torch\n",
    "import torch.nn as nn\n",
    "import math\n",
    "import torch.nn.functional as F\n",
    "import pathlib\n",
    "\n",
    "\n",
    "num_num = 2\n",
    "epochs =40\n",
    "if num_num == 1:\n",
    "    batch_size = 8\n",
    "    # lr=0.004 about 59%\n",
    "    lr=0.001\n",
    "    momentum=0.9\n",
    "else:\n",
    "    batch_size = 8\n",
    "    lr=0.0015\n",
    "    momentum=0.9\n",
    "\n",
    "\n",
    "\n",
    "if torch.cuda.is_available():\n",
    "    device = torch.device('cuda')\n",
    "else:\n",
    "    device = torch.device('cpu')\n",
    "\n",
    "print('Using PyTorch version:', torch.__version__, ' Device:', device)\n",
    "#1.load data\n",
    "transform = transforms.Compose(\n",
    "    [transforms.ToTensor(),\n",
    "    transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))])\n",
    "\n",
    "\n",
    "#这是已经划分好训练和测试数据集了的\n",
    "'''\n",
    "trainset = torchvision.datasets.CIFAR100(root='../../kaggle/input/input/archive', train=True,\n",
    "                                        download=False, transform=transform)\n",
    "#trainset = pathlib.Path('kaggle/input/input/archive/train')\n",
    "trainloader = torch.utils.data.DataLoader(trainset, batch_size=batch_size,\n",
    "                                        shuffle=True, num_workers=2)\n",
    "\n",
    "testset = torchvision.datasets.CIFAR100(root='../../kaggle/input/input/archive', train=False,\n",
    "                                    download=False, transform=transform)\n",
    "#testset = pathlib.Path('kaggle/input/input/archive/test')\n",
    "testloader = torch.utils.data.DataLoader(testset, batch_size=batch_size,\n",
    "                                        shuffle=False, num_workers=2)\n",
    "'''\n",
    "trainset = torchvision.datasets.CIFAR100(root='../input/cifar100', train=True,\n",
    "                                        download=True, transform=transform)\n",
    "trainloader = torch.utils.data.DataLoader(trainset, batch_size=batch_size,\n",
    "                                          shuffle=True, num_workers=2)\n",
    "testset = torchvision.datasets.CIFAR100(root='../input/cifar100', train=False,\n",
    "                                       download=True, transform=transform)\n",
    "testloader = torch.utils.data.DataLoader(testset, batch_size=batch_size,\n",
    "                                         shuffle=False, num_workers=2)\n",
    "\n",
    "classes = {19: 'cattle', 29: 'dinosaur', 0: 'apple', 11: 'boy', 1: 'aquarium_fish', 86: 'telephone',\n",
    "        90: 'train', 28: 'cup', 23: 'cloud', 31: 'elephant', 39: 'keyboard', 96: 'willow_tree',\n",
    "        82: 'sunflower', 17: 'castle', 71: 'sea', 8: 'bicycle', 97: 'wolf', 80: 'squirrel',\n",
    "        74: 'shrew', 59: 'pine_tree', 70: 'rose', 87: 'television', 84: 'table', 64: 'possum',\n",
    "        52: 'oak_tree', 42: 'leopard', 47: 'maple_tree', 65: 'rabbit', 21: 'chimpanzee',\n",
    "        22: 'clock', 81: 'streetcar', 24: 'cockroach', 78: 'snake', 45: 'lobster', 49: 'mountain',\n",
    "        56: 'palm_tree', 76: 'skyscraper', 89: 'tractor', 73: 'shark', 14: 'butterfly', 9: 'bottle',\n",
    "        6: 'bee', 20: 'chair', 98: 'woman', 36: 'hamster', 55: 'otter', 72: 'seal', 43: 'lion', 51: 'mushroom',\n",
    "        35: 'girl', 83: 'sweet_pepper', 33: 'forest', 27: 'crocodile', 53: 'orange', 92: 'tulip', 50: 'mouse',\n",
    "        15: 'camel', 18: 'caterpillar', 46: 'man', 75: 'skunk', 38: 'kangaroo', 66: 'raccoon', 77: 'snail',\n",
    "        69: 'rocket', 95: 'whale', 99: 'worm', 93: 'turtle', 4: 'beaver', 61: 'plate', 94: 'wardrobe', 68: 'road',\n",
    "        34: 'fox', 32: 'flatfish', 88: 'tiger', 67: 'ray', 30: 'dolphin', 62: 'poppy', 63: 'porcupine', 40: 'lamp',\n",
    "        26: 'crab', 48: 'motorcycle', 79: 'spider', 85: 'tank', 54: 'orchid', 44: 'lizard', 7: 'beetle', 12: 'bridge',\n",
    "        2: 'baby', 41: 'lawn_mower', 37: 'house', 13: 'bus', 25: 'couch', 10: 'bowl', 57: 'pear', 5: 'bed',\n",
    "        60: 'plain', 91: 'trout', 3: 'bear', 58: 'pickup_truck', 16: 'can'}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "454c52f2",
   "metadata": {},
   "outputs": [],
   "source": [
    "#Note that the org code if from https://github.com/houqb/CoordAttention/blob/main/coordatt.py\n",
    "class h_sigmoid(nn.Module):     #通过ReLU6函数实现，将输入的值限制在0到6之间，并输出在0到1之间的值。\n",
    "    def __init__(self, inplace=True):\n",
    "        super(h_sigmoid, self).__init__()\n",
    "        self.relu = nn.ReLU6(inplace=inplace)\n",
    "\n",
    "    def forward(self, x):\n",
    "        return self.relu(x + 3) / 6\n",
    "\n",
    "class h_swish(nn.Module):#激活函数，通过对输入进行 h_sigmoid 操作后，将输入乘以激活函数的输出。\n",
    "    def __init__(self, inplace=True):\n",
    "        super(h_swish, self).__init__()\n",
    "        self.sigmoid = h_sigmoid(inplace=inplace)\n",
    "\n",
    "    def forward(self, x):\n",
    "        return x * self.sigmoid(x)\n",
    "\n",
    "#通道注意力\n",
    "class ChannelAtt(nn.Module):\n",
    "    def __init__(self, channels, reduction=32):\n",
    "        super(ChannelAtt, self).__init__()\n",
    "        self.avg_pool = nn.AdaptiveAvgPool2d(1)\n",
    "        self.fc = nn.Sequential(\n",
    "            nn.Linear(channels, channels // reduction),\n",
    "            nn.ReLU(inplace=True),\n",
    "            nn.Linear(channels // reduction, channels),\n",
    "            nn.Sigmoid()\n",
    "        )\n",
    "\n",
    "    def forward(self, x):\n",
    "        b, c, _, _ = x.size()\n",
    "        y = self.avg_pool(x).view(b, c)\n",
    "        y = self.fc(y).view(b, c, 1, 1)\n",
    "       # 将通道注意力权重复制到与输入特征图相同的维度上\n",
    "        y = y.expand_as(x)\n",
    "        return x * y\n",
    "\n",
    "\n",
    "class CoordAtt(nn.Module):\n",
    "    def __init__(self, inp, oup, reduction=32):\n",
    "        super(CoordAtt, self).__init__()\n",
    "        self.pool_h = nn.AdaptiveAvgPool2d((None, 1))\n",
    "        self.pool_w = nn.AdaptiveAvgPool2d((1, None))\n",
    "\n",
    "        mip = max(8, inp // reduction)#一个降维比例 reduction 作为参数。\n",
    "\n",
    "        self.conv1 = nn.Conv2d(inp, mip, kernel_size=1, stride=1, padding=0)\n",
    "        self.bn1 = nn.BatchNorm2d(mip)\n",
    "        self.act = h_swish()\n",
    "        \n",
    "        #conv_h 和 conv_w 是两个1x1的卷积层，分别用于生成垂直和水平方向的注意力权重。\n",
    "        self.conv_h = nn.Conv2d(mip, oup, kernel_size=1, stride=1, padding=0)\n",
    "        self.conv_w = nn.Conv2d(mip, oup, kernel_size=1, stride=1, padding=0)\n",
    "        #self.ca = ChannelAtt(oup)  # 添加通道注意力模块\n",
    "        \n",
    "\n",
    "    def forward(self, x):\n",
    "        identity = x\n",
    "        \n",
    "        #对输入在垂直和水平方向进行自适应平均池化操作，得到 x_h 和 x_w。\n",
    "        n,c,h,w = x.size()\n",
    "        x_h = self.pool_h(x)\n",
    "        x_w = self.pool_w(x).permute(0, 1, 3, 2)\n",
    "        \n",
    "        #h、w方向进行拼接 得到注意力特征图y\n",
    "        y = torch.cat([x_h, x_w], dim=2)\n",
    "        y = self.conv1(y)\n",
    "        y = self.bn1(y)\n",
    "        y = self.act(y) \n",
    "        \n",
    "        x_h, x_w = torch.split(y, [h, w], dim=2)\n",
    "        x_w = x_w.permute(0, 1, 3, 2)\n",
    "        \n",
    "        #生成权重注意力\n",
    "        a_h = self.conv_h(x_h).sigmoid()\n",
    "        a_w = self.conv_w(x_w).sigmoid()\n",
    "\n",
    "        out = identity * a_w * a_h\n",
    "        #out = self.ca(out)  # 应用通道注意力\n",
    "\n",
    "        return out"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "73f0746b",
   "metadata": {},
   "outputs": [],
   "source": [
    "class Bottleneck(nn.Module):\n",
    "    expansion = 4\n",
    "\n",
    "    def __init__(self, inplanes, planes, stride=1, downsample=None):\n",
    "        super(Bottleneck, self).__init__()\n",
    "        self.conv1 = nn.Conv2d(inplanes, planes, kernel_size=1, bias=False)\n",
    "        self.bn1 = nn.BatchNorm2d(planes)\n",
    "        self.conv2 = nn.Conv2d(planes, planes, kernel_size=3, stride=stride,\n",
    "                               padding=1, bias=False)\n",
    "        #self.ca = CoordAtt(planes, planes)\n",
    "        self.bn2 = nn.BatchNorm2d(planes)\n",
    "        self.conv3 = nn.Conv2d(planes, planes*4, kernel_size=1, bias=False)\n",
    "        self.bn3 = nn.BatchNorm2d(planes*4)\n",
    "        self.relu = nn.ReLU(inplace=True)\n",
    "        self.downsample = downsample\n",
    "        self.stride = stride\n",
    "        self.shortcut = nn.Sequential()\n",
    "        \n",
    "\n",
    "\n",
    "        if stride != 1 or inplanes != planes * Bottleneck.expansion:\n",
    "            self.shortcut = nn.Sequential(\n",
    "                nn.Conv2d(inplanes,\n",
    "                          planes * Bottleneck.expansion,\n",
    "                          stride=stride,\n",
    "                          kernel_size=1,\n",
    "                          bias=False),\n",
    "                nn.BatchNorm2d(planes * Bottleneck.expansion))\n",
    "\n",
    "    def forward(self, x):\n",
    "        # residual = x\n",
    "\n",
    "        out = self.conv1(x)\n",
    "        out = self.bn1(out)\n",
    "        out = self.relu(out)\n",
    "\n",
    "        out = self.conv2(out)\n",
    "        #out=self.ca(out)\n",
    "        out = self.bn2(out)\n",
    "        out = self.relu(out)\n",
    "\n",
    "        out = self.conv3(out)\n",
    "        out = self.bn3(out)\n",
    "\n",
    "        # if self.downsample is not None:\n",
    "        #     residual = self.downsample(x)\n",
    "\n",
    "        # out += residual\n",
    "        #加上CA模块 v1\n",
    "        \n",
    "        out+=self.shortcut(x)\n",
    "        out = self.relu(out)\n",
    "\n",
    "        return out\n",
    "\n",
    "\n",
    "class Net(nn.Module):\n",
    "    def __init__(self, block, num_blocks, num_classes=100,use_gcblock=True):\n",
    "        super(Net, self).__init__()\n",
    "        self.use_gcblock=use_gcblock\n",
    "\n",
    "        self.in_channel = 64\n",
    "\n",
    "        self.conv1 = nn.Conv2d(3, 64, kernel_size=3,\n",
    "                               stride=1, padding=1, bias=False)\n",
    "        self.bn1 = nn.BatchNorm2d(64)\n",
    "\n",
    "        self.layer1 = self.make_layer(block, 64, num_blocks[0], stride=1)\n",
    "        self.layer2 = self.make_layer(block, 128, num_blocks[1], stride=2)\n",
    "        self.layer3 = self.make_layer(block, 256, num_blocks[2], stride=2)\n",
    "        self.layer4 = self.make_layer(block, 512, num_blocks[3], stride=2)\n",
    "\n",
    "        self.fc10=nn.Linear(256,256)\n",
    "        self.fc1=nn.Linear(256,512)\n",
    "\n",
    "        self.fc20=nn.Linear(512,512)\n",
    "        self.fc2=nn.Linear(512,1024)\n",
    "\n",
    "        self.fc30=nn.Linear(1024,1024)\n",
    "        self.fc3=nn.Linear(1024,2048)\n",
    "\n",
    "        self.relu = nn.ReLU(inplace=True)\n",
    "\n",
    "        self.linear = nn.Linear(512 * block.expansion, num_classes)\n",
    "\n",
    "    def make_layer(self, block, out_channel, num_blocks, stride):\n",
    "        strides = [stride] + (num_blocks - 1) * [1]\n",
    "        layers = []\n",
    "        for stride in strides:\n",
    "            layers.append(block(self.in_channel, out_channel, stride))\n",
    "            self.in_channel = out_channel * block.expansion\n",
    "        return nn.Sequential(*layers)\n",
    "\n",
    "    def forward(self, x):\n",
    "        out = F.relu(self.bn1(self.conv1(x)))\n",
    "        out = self.layer1(out)\n",
    "        out = self.layer2(out)\n",
    "        out = self.layer3(out)\n",
    "        out = self.layer4(out)\n",
    "        out = F.avg_pool2d(out, 4)\n",
    "        out = out.view(out.size(0), -1)\n",
    "        out = self.linear(out)\n",
    "        return out\n",
    "\n",
    "\n",
    "def ResNet():\n",
    "    return Net(Bottleneck, [2, 2, 2,2])#resNet18：用瓶颈网"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "d6435cb5",
   "metadata": {},
   "outputs": [],
   "source": [
    "net = ResNet().to(device)\n",
    "print(net)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "6b30d168",
   "metadata": {},
   "outputs": [],
   "source": [
    "criterion = nn.CrossEntropyLoss()\n",
    "optimizer = optim.SGD(net.parameters(), lr=lr, momentum=momentum)\n",
    "\n",
    "#开始训练\n",
    "loss_vector, accuracy_vector = [], []\n",
    "for epoch in range(epochs):\n",
    "    #训练\n",
    "    net.train()\n",
    "    running_loss = 0.0\n",
    "    total=0\n",
    "    running_loss = 0.0\n",
    "    correct=0\n",
    "    for i, data in enumerate(trainloader, 0):\n",
    "        # get the inputs; data is a list of [inputs, labels]\n",
    "        inputs, labels = data\n",
    "        inputs = inputs.to(device)\n",
    "        labels = labels.to(device)\n",
    "\n",
    "        # zero the parameter gradients\n",
    "        optimizer.zero_grad()\n",
    "\n",
    "        # forward + backward + optimize\n",
    "        outputs = net(inputs)\n",
    "        loss = criterion(outputs, labels)\n",
    "        loss.backward()\n",
    "        optimizer.step()\n",
    "\n",
    "        # print statistics\n",
    "        running_loss += loss.item()\n",
    "        _, predicted = torch.max(outputs.data, 1)\n",
    "        total += labels.size(0)\n",
    "        correct += predicted.eq(labels.data).sum()\n",
    "        if i % 2000 == 1999:    # print every 2000 mini-batches\n",
    "            print(f'[{epoch+1}, {i+1:5d}] loss: {running_loss / 2000:.3f},Train accuracy:{100*correct/total:.2f}')\n",
    "            total=0;\n",
    "            running_loss = 0.0\n",
    "            correct=0\n",
    "\n",
    "\n",
    "    # 每训练完一个epoch测试一下准确率\n",
    "    #测试不需要反向计算梯度：提高效率\n",
    "    with torch.no_grad():\n",
    "        net.eval()\n",
    "        total = 0\n",
    "        val_loss, correct = 0, 0\n",
    "        for data, target in testloader:\n",
    "            data = data.to(device)\n",
    "            target = target.to(device)\n",
    "            output = net(data)\n",
    "            val_loss += criterion(output, target).data.item()\n",
    "            _, predicted = torch.max(output.data, 1)\n",
    "            correct += (predicted == target).sum().item()\n",
    "            total += target.size(0)#total就是一个 总数...\n",
    "\n",
    "        val_loss /= total\n",
    "        loss_vector.append(val_loss)\n",
    "\n",
    "        accuracy = 100 * correct / total\n",
    "        accuracy_vector.append(accuracy)\n",
    "\n",
    "        print('\\nValidation set: Average loss: {:.4f}, Accuracy: {}/{} ({:.0f}%)\\n'.format(\n",
    "            val_loss, correct, total, accuracy))\n",
    "\n",
    "print(\"training finished！\")\n",
    "#for name, paramer in net.named_parameters():\n",
    "            #print(name, paramer)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "e493e029",
   "metadata": {},
   "outputs": [],
   "source": [
    "print(\"training finished！\")\n",
    "\n",
    "plt.figure(figsize=(5,3))\n",
    "plt.plot(np.arange(1,epochs+1), loss_vector)\n",
    "plt.title('validation loss,epoch=%s'%epochs)\n",
    "\n",
    "plt.figure(figsize=(5,3))\n",
    "plt.plot(np.arange(1,epochs+1), accuracy_vector)\n",
    "plt.title('validation accuracy,epoch=%s'%epochs)\n",
    "\n",
    "#prec1, prec5 = accuracy(output.data, target, topk=(1, 5))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "id": "a9329e77",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[1,  1000] loss: 4.324\n",
      "[1,  2000] loss: 4.068\n",
      "[1,  3000] loss: 3.936\n",
      "[1,  4000] loss: 3.804\n",
      "[1,  5000] loss: 3.693\n",
      "[1,  6000] loss: 3.545\n",
      "\n",
      "Validation set: Average loss: 0.4242, Accuracy: 1714/10000 (17%)\n",
      "\n",
      "[2,  1000] loss: 3.554\n",
      "[2,  2000] loss: 3.355\n",
      "[2,  3000] loss: 3.208\n",
      "[2,  4000] loss: 3.137\n",
      "[2,  5000] loss: 3.043\n",
      "[2,  6000] loss: 2.971\n",
      "\n",
      "Validation set: Average loss: 0.3507, Accuracy: 2802/10000 (28%)\n",
      "\n",
      "[3,  1000] loss: 2.794\n",
      "[3,  2000] loss: 2.696\n",
      "[3,  3000] loss: 2.630\n",
      "[3,  4000] loss: 2.576\n",
      "[3,  5000] loss: 2.522\n",
      "[3,  6000] loss: 2.458\n",
      "\n",
      "Validation set: Average loss: 0.3064, Accuracy: 3531/10000 (35%)\n",
      "\n",
      "[4,  1000] loss: 2.246\n",
      "[4,  2000] loss: 2.223\n",
      "[4,  3000] loss: 2.195\n",
      "[4,  4000] loss: 2.176\n",
      "[4,  5000] loss: 2.131\n",
      "[4,  6000] loss: 2.108\n",
      "\n",
      "Validation set: Average loss: 0.2658, Accuracy: 4236/10000 (42%)\n",
      "\n",
      "[5,  1000] loss: 1.840\n",
      "[5,  2000] loss: 1.853\n",
      "[5,  3000] loss: 1.856\n",
      "[5,  4000] loss: 1.850\n",
      "[5,  5000] loss: 1.832\n",
      "[5,  6000] loss: 1.798\n",
      "\n",
      "Validation set: Average loss: 0.2390, Accuracy: 4766/10000 (48%)\n",
      "\n",
      "[6,  1000] loss: 1.494\n",
      "[6,  2000] loss: 1.545\n",
      "[6,  3000] loss: 1.543\n",
      "[6,  4000] loss: 1.552\n",
      "[6,  5000] loss: 1.532\n",
      "[6,  6000] loss: 1.539\n",
      "\n",
      "Validation set: Average loss: 0.2309, Accuracy: 4967/10000 (50%)\n",
      "\n",
      "[7,  1000] loss: 1.209\n",
      "[7,  2000] loss: 1.252\n",
      "[7,  3000] loss: 1.280\n",
      "[7,  4000] loss: 1.286\n",
      "[7,  5000] loss: 1.304\n",
      "[7,  6000] loss: 1.313\n",
      "\n",
      "Validation set: Average loss: 0.2309, Accuracy: 5062/10000 (51%)\n",
      "\n",
      "[8,  1000] loss: 0.927\n",
      "[8,  2000] loss: 1.008\n",
      "[8,  3000] loss: 1.041\n",
      "[8,  4000] loss: 1.037\n",
      "[8,  5000] loss: 1.049\n",
      "[8,  6000] loss: 1.061\n",
      "\n",
      "Validation set: Average loss: 0.2346, Accuracy: 5209/10000 (52%)\n",
      "\n",
      "[9,  1000] loss: 0.695\n",
      "[9,  2000] loss: 0.755\n",
      "[9,  3000] loss: 0.814\n",
      "[9,  4000] loss: 0.838\n",
      "[9,  5000] loss: 0.845\n",
      "[9,  6000] loss: 0.851\n",
      "\n",
      "Validation set: Average loss: 0.2334, Accuracy: 5224/10000 (52%)\n",
      "\n",
      "[10,  1000] loss: 0.522\n",
      "[10,  2000] loss: 0.567\n",
      "[10,  3000] loss: 0.643\n",
      "[10,  4000] loss: 0.656\n",
      "[10,  5000] loss: 0.670\n",
      "[10,  6000] loss: 0.704\n",
      "\n",
      "Validation set: Average loss: 0.2515, Accuracy: 5115/10000 (51%)\n",
      "\n",
      "[11,  1000] loss: 0.396\n",
      "[11,  2000] loss: 0.445\n",
      "[11,  3000] loss: 0.493\n",
      "[11,  4000] loss: 0.512\n",
      "[11,  5000] loss: 0.557\n",
      "[11,  6000] loss: 0.548\n",
      "\n",
      "Validation set: Average loss: 0.2519, Accuracy: 5278/10000 (53%)\n",
      "\n",
      "[12,  1000] loss: 0.283\n",
      "[12,  2000] loss: 0.352\n",
      "[12,  3000] loss: 0.388\n",
      "[12,  4000] loss: 0.402\n",
      "[12,  5000] loss: 0.427\n",
      "[12,  6000] loss: 0.431\n",
      "\n",
      "Validation set: Average loss: 0.2799, Accuracy: 5070/10000 (51%)\n",
      "\n",
      "[13,  1000] loss: 0.232\n",
      "[13,  2000] loss: 0.291\n",
      "[13,  3000] loss: 0.295\n",
      "[13,  4000] loss: 0.337\n",
      "[13,  5000] loss: 0.325\n",
      "[13,  6000] loss: 0.357\n",
      "\n",
      "Validation set: Average loss: 0.3022, Accuracy: 5112/10000 (51%)\n",
      "\n",
      "[14,  1000] loss: 0.203\n",
      "[14,  2000] loss: 0.261\n",
      "[14,  3000] loss: 0.247\n",
      "[14,  4000] loss: 0.286\n",
      "[14,  5000] loss: 0.306\n",
      "[14,  6000] loss: 0.301\n",
      "\n",
      "Validation set: Average loss: 0.3083, Accuracy: 5190/10000 (52%)\n",
      "\n",
      "[15,  1000] loss: 0.150\n",
      "[15,  2000] loss: 0.190\n",
      "[15,  3000] loss: 0.221\n",
      "[15,  4000] loss: 0.212\n",
      "[15,  5000] loss: 0.235\n",
      "[15,  6000] loss: 0.254\n",
      "\n",
      "Validation set: Average loss: 0.3263, Accuracy: 5159/10000 (52%)\n",
      "\n",
      "Training Finished\n"
     ]
    }
   ],
   "source": [
    "from torchsummary import summary\n",
    "\n",
    "# 需要使用device来指定网络在GPU还是CPU运行\n",
    "summary(net ,(3,32,32))\n"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "id": "ecf62cce",
   "metadata": {},
   "source": [
    "Let’s quickly save our trained model:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "id": "9d94a16d",
   "metadata": {},
   "outputs": [],
   "source": [
    "from thop import profile\n",
    "\n",
    "inputs = torch.randn(1, 3, 32, 32)\n",
    "inputs=inputs.to(device)\n",
    "flops, params = profile(net, inputs=(inputs,))\n",
    "print('FLOPs = ' + str(flops/1000**3) + 'G')\n",
    "print('Params = ' + str(params/1000**2) + 'M')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "909e084f",
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.10.5"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
